package svnserver.service;

import org.jetbrains.annotations.NotNull;
import org.mapdb.DB;
import org.mapdb.DBException;
import org.mapdb.DBMaker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import svnserver.server.SvnServer;

import java.io.File;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

public class Parameters {
  //
  static private Parameters inst_ = null;
  private static final Logger log = LoggerFactory.getLogger(SvnServer.class);

  private boolean InitializeLocalAddress() {
    // Preferred local address initialized
    String addrenv = System.getenv("GITEE_RIME_PREFERRED_LOCAL");
    if (addrenv != null && addrenv.length() > 0) {
      localAddress = addrenv;
      return true;
    }
    try {
      final Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
      while (e.hasMoreElements()) {
        final NetworkInterface n = (NetworkInterface) e.nextElement();
        final Enumeration<InetAddress> ee = n.getInetAddresses();
        while (ee.hasMoreElements()) {
          final InetAddress i = (InetAddress) ee.nextElement();
          final String addr = i.getHostAddress();
          if (addr.startsWith("192.168.")) {
            localAddress = addr;
            return true;
          }
        }
      }
    } catch (final Exception e) {
      log.error("InitializeLocalAddress", e);
      return false;
    }
    return true;
  }

  public static boolean Initialize(@NotNull final String file) {
    final TomlUtils utils = new TomlUtils();
    if (!utils.ParseFile(file, false)) {
      return false;
    }
    inst_ = new Parameters();
    inst_.shuttime = utils.get("Service.ShutdownTimeout", 10l);
    inst_.urlPrefix = utils.get("Service.ApiPrefix", "http://gitee.com/api/v3/");
    inst_.domain = utils.get("Service.Domain", "gitee.com");
    inst_.deadline = (int) utils.get("Service.Deadline", 1800l); // 1800s
    final long MP = Runtime.getRuntime().availableProcessors();
    inst_.threads = (int) utils.get("App.Threads", MP);
    inst_.port = (int) utils.get("App.Port", 3690l);
    inst_.address = utils.get("App.Address", "0.0.0.0");
    inst_.root = utils.get("App.Root", "/home/git/repositories/");
    inst_.useCachedThreadPool = utils.get("App.UseCachedThreadPool", false);
    inst_.filterDomain = utils.get("App.FilterDomain", false);
    /// flags
    inst_.enableSizeEvent = utils.get("App.EnableSizeEvent", false);
    inst_.enableRime = utils.get("App.EnableRime", false);
    inst_.redisServer = utils.get("App.RedisServer", "redis://127.0.0.1:6379");
    inst_.redisRime = utils.get("App.RedisRime", "redis://127.0.0.1:6379");
    if (inst_.enableRime) {
      inst_.rimeName = System.getenv("GITEE_RIME_NAME");
      if (inst_.rimeName == null || inst_.rimeName.length() == 0) {
        inst_.rimeName = utils.get("App.RimeName", "");
      }
      // resolve local address
      if (inst_.InitializeLocalAddress()) {
        log.info("resolve local address {}", inst_.localAddress);
      }
    }
    inst_.sshallowed = utils.get("SSH.Allowed", false);
    inst_.sshusetoken = utils.get("SSH.UseToken", true);
    inst_.sshtoken = utils.get("SSH.Token", "");
    try {
      final File f = new File(file);
      inst_.basePath = f.getAbsoluteFile().getParentFile();
    } catch (final Exception e) {
      log.error("Initialize", e);
      return false;
    }
    return true;
  }

  @NotNull
  public static Parameters Get() {
    return inst_;
  }

  public long Shuttime() {
    return shuttime;
  }

  public String URLPrefix() {
    return urlPrefix;
  }

  public int Threads() {
    return threads;
  }

  public String Domain() {
    return domain;
  }

  public String getRoot() {
    return root;
  }

  public String RedisServer() {
    return redisServer;
  }

  public String RedisRime() {
    return redisRime;
  }

  public String LocalAddress() {
    return localAddress;
  }

  public int Port() {
    return port;
  }

  public String ListenAddress() {
    return address;
  }

  public String RimeName() {
    return rimeName;
  }

  public int Deadline() {
    return deadline;
  }

  public boolean IsUseCachedThreadPool() {
    return useCachedThreadPool;
  }

  public boolean EnableSizeEvent() {
    return enableSizeEvent;
  }

  public boolean EnableRime() {
    return enableRime;
  }

  public boolean IsFilterDomain() {
    return filterDomain;
  }

  @NotNull
  public File BasePath() {
    return basePath;
  }

  public boolean SshIsAllowed() {
    return sshallowed;
  }

  public boolean SshNeedToken() {
    return sshusetoken;
  }

  @NotNull
  public String SshToken() {
    return sshtoken;
  }

  private String urlPrefix;
  private String domain;
  private String address;
  private String root;
  private String redisServer;
  private String redisRime;
  private String localAddress;
  private String rimeName;
  private int port;
  private int threads;
  private int deadline;
  private long shuttime;
  private File basePath;
  private boolean useCachedThreadPool;
  private boolean filterDomain;
  private boolean enableSizeEvent;
  private boolean enableRime;
  private boolean sshallowed;
  private boolean sshusetoken;
  private String sshtoken;

  @NotNull
  public static File joinPath(@NotNull final File basePath, @NotNull final String localPath) {
    final File path = new File(localPath);
    return path.isAbsolute() ? path : new File(basePath, localPath);
  }

  @NotNull
  static public DB createCache(@NotNull final File basePath) {
    try {
      return DBMaker.fileDB(joinPath(basePath, "svn-cache.db")).closeOnJvmShutdown().fileMmapEnableIfSupported().make();
    } catch (final DBException e) {
      throw new DBException(String.format("Failed to open %s: %s", basePath, e.getMessage()), e);
    }
  }
}
